def ci_setup(image) {
  sh (
    script: "${docker_run} ${image} ./tests/scripts/task_ci_setup.sh",
    label: 'Set up CI environment',
  )
}

def python_unittest(image) {
  sh (
    script: "${docker_run} ${image} ./tests/scripts/task_python_unittest.sh",
    label: 'Run Python unit tests',
  )
}

def fsim_test(image) {
  sh (
    script: "${docker_run} ${image} ./tests/scripts/task_python_vta_fsim.sh",
    label: 'Run VTA tests in FSIM',
  )
}

def cmake_build(image, path, make_flag) {
  sh (
    script: "${docker_run} --env CI_NUM_EXECUTORS ${image} ./tests/scripts/task_build.py --sccache-bucket tvm-sccache-prod",
    label: 'Run cmake build',
  )
}

def cpp_unittest(image) {
  sh (
    script: "${docker_run} --env CI_NUM_EXECUTORS ${image} ./tests/scripts/task_cpp_unittest.sh",
    label: 'Build and run C++ tests',
  )
}


def add_microtvm_permissions() {
  {% for folder in microtvm_template_projects %}
  sh(
    script: 'find {{ folder }} -type f | grep qemu-hack | xargs chmod +x',
    label: 'Add execute permissions for microTVM files',
  )
  {% endfor %}
}

def add_hexagon_permissions() {
  {% for folder in hexagon_api %}
  sh(
    script: 'find {{ folder }} -type f | xargs chmod +x',
    label: 'Add execute permissions for hexagon files',
  )
  {% endfor %}
}

// Run make. First try to do an incremental make from a previous workspace in hope to
// accelerate the compilation. If something is wrong, clean the workspace and then
// build from scratch.
def make(docker_type, path, make_flag) {
  timeout(time: max_time, unit: 'MINUTES') {
    try {
      cmake_build(docker_type, path, make_flag)
    } catch (hudson.AbortException ae) {
      // script exited due to user abort, directly throw instead of retry
      if (ae.getMessage().contains('script returned exit code 143')) {
        throw ae
      }
      echo 'Incremental compilation failed. Fall back to build from scratch'
      sh (
        script: "${docker_run} ${docker_type} ./tests/scripts/task_clean.sh ${path}",
        label: 'Clear old cmake workspace',
      )
      cmake_build(docker_type, path, make_flag)
    }
  }
}


def build() {
stage('Build') {
  environment {
    SKIP_SLOW_TESTS = "${skip_slow_tests}"
  }
  parallel(
    'BUILD: GPU': {
    if (!skip_ci) {
      node('CPU-SMALL') {
        ws({{ m.per_exec_ws('tvm/build-gpu') }}) {
          docker_init(ci_gpu)
          init_git()
          sh "${docker_run} --no-gpu ${ci_gpu} ./tests/scripts/task_config_build_gpu.sh build"
          make("${ci_gpu} --no-gpu", 'build', '-j2')
          {{ m.upload_artifacts(tag='gpu', filenames=tvm_multilib, folders=microtvm_template_projects) }}

          // compiler test
          sh "${docker_run} --no-gpu ${ci_gpu} ./tests/scripts/task_config_build_gpu_other.sh build2"
          make("${ci_gpu} --no-gpu", 'build2', '-j2')
          {{ m.upload_artifacts(tag='gpu2', filenames=tvm_multilib) }}
        }
      }
    }
  },
  'BUILD: CPU': {
    if (!skip_ci && is_docs_only_build != 1) {
      node('CPU-SMALL') {
        ws({{ m.per_exec_ws('tvm/build-cpu') }}) {
          docker_init(ci_cpu)
          init_git()
          sh (
            script: "${docker_run} ${ci_cpu} ./tests/scripts/task_config_build_cpu.sh build",
            label: 'Create CPU cmake config',
          )
          make(ci_cpu, 'build', '-j2')
          {{ m.upload_artifacts(tag='cpu', filenames=tvm_multilib_tsim) }}
          timeout(time: max_time, unit: 'MINUTES') {
            ci_setup(ci_cpu)
            // sh "${docker_run} ${ci_cpu} ./tests/scripts/task_golang.sh"
            // TODO(@jroesch): need to resolve CI issue will turn back on in follow up patch
            sh (script: "${docker_run} ${ci_cpu} ./tests/scripts/task_rust.sh", label: 'Rust build and test')
          }
        }
      }
    } else {
      Utils.markStageSkippedForConditional('BUILD: CPU')
    }
  },
  'BUILD: WASM': {
    if (!skip_ci && is_docs_only_build != 1) {
      node('CPU-SMALL') {
        ws({{ m.per_exec_ws('tvm/build-wasm') }}) {
          docker_init(ci_wasm)
          init_git()
          sh (
            script: "${docker_run} ${ci_wasm} ./tests/scripts/task_config_build_wasm.sh build",
            label: 'Create WASM cmake config',
          )
          make(ci_wasm, 'build', '-j2')
          cpp_unittest(ci_wasm)
          timeout(time: max_time, unit: 'MINUTES') {
            ci_setup(ci_wasm)
            sh (
              script: "${docker_run} ${ci_wasm} ./tests/scripts/task_web_wasm.sh",
              label: 'Run WASM lint and tests',
            )
          }
        }
      }
    } else {
      Utils.markStageSkippedForConditional('BUILD: WASM')
    }
  },
  'BUILD: i386': {
    if (!skip_ci && is_docs_only_build != 1) {
      node('CPU-SMALL') {
        ws({{ m.per_exec_ws('tvm/build-i386') }}) {
          docker_init(ci_i386)
          init_git()
          sh (
            script: "${docker_run} ${ci_i386} ./tests/scripts/task_config_build_i386.sh build",
            label: 'Create i386 cmake config',
          )
          make(ci_i386, 'build', '-j2')
          {{ m.upload_artifacts(tag='i386', filenames=tvm_multilib_tsim) }}
        }
      }
    } else {
      Utils.markStageSkippedForConditional('BUILD: i386')
    }
  },
  'BUILD: arm': {
    if (!skip_ci && is_docs_only_build != 1) {
      node('ARM-SMALL') {
        ws({{ m.per_exec_ws('tvm/build-arm') }}) {
          docker_init(ci_arm)
          init_git()
          sh (
            script: "${docker_run} ${ci_arm} ./tests/scripts/task_config_build_arm.sh build",
            label: 'Create ARM cmake config',
          )
          make(ci_arm, 'build', '-j4')
          {{ m.upload_artifacts(tag='arm', filenames=tvm_multilib) }}
        }
      }
     } else {
      Utils.markStageSkippedForConditional('BUILD: arm')
    }
  },
  'BUILD: QEMU': {
    if (!skip_ci && is_docs_only_build != 1) {
      node('CPU-SMALL') {
        ws({{ m.per_exec_ws('tvm/build-qemu') }}) {
          docker_init(ci_qemu)
          init_git()
          sh (
            script: "${docker_run} ${ci_qemu} ./tests/scripts/task_config_build_qemu.sh build",
            label: 'Create QEMU cmake config',
          )
          make(ci_qemu, 'build', '-j2')
          {{ m.upload_artifacts(tag='qemu', filenames=tvm_lib, folders=microtvm_template_projects) }}
        }
      }
     } else {
      Utils.markStageSkippedForConditional('BUILD: QEMU')
    }
  },
  'BUILD: Hexagon': {
    if (!skip_ci && is_docs_only_build != 1) {
      node('CPU-SMALL') {
        ws({{ m.per_exec_ws('tvm/build-hexagon') }}) {
          docker_init(ci_hexagon)
          init_git()
          sh (
            script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_config_build_hexagon.sh build",
            label: 'Create Hexagon cmake config',
          )
          make(ci_hexagon, 'build', '-j2')
          sh (
            script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_build_hexagon_api.sh",
            label: 'Build Hexagon API',
          )
          {{ m.upload_artifacts(tag='hexagon', filenames=tvm_lib, folders=hexagon_api) }}
        }
      }
     } else {
      Utils.markStageSkippedForConditional('BUILD: Hexagon')
    }
  },
  )
}
}
